package io.bdmc.modules.bss.controller;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.bdmc.common.exception.FileLengthNotEnoughException;
import io.bdmc.common.utils.*;
import io.bdmc.common.validator.Assert;
import io.bdmc.modules.bss.entity.*;
import io.bdmc.modules.bss.model.DeviceMeasureParam;
import io.bdmc.modules.bss.model.MeasureArgs;
import io.bdmc.modules.bss.model.SorFileParser;
import io.bdmc.modules.bss.service.*;
import io.bdmc.modules.sys.controller.AbstractController;
import io.bdmc.core.udp.UdpClientSendData;
import io.bdmc.core.msp2000.utils.FmsDeviceUtil;
import io.bdmc.core.msp2000.utils.OswDeviceUtil;
import io.bdmc.core.snmp.SORFileParserTool;
import io.bdmc.core.snmp.cache.ConcurrentHashMapCacheUtils;

import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellStyle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 前端控制器
 * </p>
 *
 * @author 黄露
 * @since 2021-06-01
 */

// "FMS设备数据")
@RestController
@RequestMapping("/bss/device/fms")
public class DeviceMachineFmsController extends AbstractController {
    @Autowired
    IDeviceMachineFmsService fmsService;

    @Autowired
    IDeviceDeviceService deviceService;

    @Autowired
    UdpClientSendData _udpClient;

    @Autowired
    IDeviceMeasureService measureService;

    @Autowired
    IDeviceMeasureEventService measureEventService;

    @Autowired
    FmsDeviceUtil fmsDeviceUtil;

    @Autowired
    IDeviceRouteConfigService routeConfigService;

    @Autowired
    IDeviceRouteService routeService;

    @Autowired
    IDeviceMachineOswService oswService;

    @Autowired
    OswDeviceUtil oswDeviceUtil;

    @GetMapping("/measure/list")
    // "FMS测试历史数据", notes = "FMS测试历史数据")
    // @RequiresPermissions("bss:device:measure:list")
    public R list(DeviceMeasureParam params) {
        MyPage<DeviceMeasure> myPage = new MyPage<>(params.getCurrent(), params.getSize());
        MyPage<DeviceMeasure> map = measureService.mySelectPage(myPage, params);
        return R.ok().putData(MyMap.ok(map.getRecords(), map.getTotal()));

    }

    @GetMapping("/measure/last")
    // "最新一条FMS测试数据", notes = "最新一条FMS测试数据")
    // @RequiresPermissions("bss:device:measure:list")
    public R lastMeasure(DeviceMeasureParam params) {
        if (params.getChannel() == null || params.getChannel() == 0) {
            params.setChannel(1);
        }
        QueryWrapper<DeviceMeasure> w1 = new QueryWrapper<DeviceMeasure>().eq("device_sn", params.getDeviceSn())
                .eq("channel", params.getChannel()).eq("measure_status", 3).orderByDesc("start_time").last("limit 1");
        if (params.getRouteId() != null && params.getRouteId() > 0) {
            w1.eq("route_id", params.getRouteId());
        }
        final DeviceMeasure deviceMeasure = measureService.getOne(w1);
        return R.ok().putData(deviceMeasure);
    }

    @PostMapping("/set")
    // "设置", notes = "设置")
    public R set(@RequestBody DeviceMachineFms fms) {
        DeviceDevice dd = deviceService.getDeviceBySn(fms.getDiskSn());
        DeviceDevice parent = deviceService.getById(dd.getParentId());
        String ip = dd.isOTDR() ? dd.getIpaddr() : parent.getIpaddr();
        int port = dd.isOTDR() ? dd.getDevicePort() : parent.getDevicePort();
        Boolean result = fmsDeviceUtil.setFmsConfig(dd.getLayerRow(), ip, port, fms.getEndPosition(),
                fms.getPulseWidth(), fms.getResolution(), dd.getDeviceType(), fms.getDiskSn());

        return R.trueOrFalse(result);
    }

    @PostMapping("/refresh")
    // "刷新信息", notes = "刷新信息")
    public R refresh(@RequestBody DeviceMachineFms fms) {
        DeviceMachineFms fmsData = fmsService.selectLastFmsData(fms.getDiskSn());
        return R.ok().putData(fmsData);
    }

    /**
     * 点名测试需要先获取路由
     */
    @PostMapping("/measure")
    // "点名测试", notes = "点名测试")
    public R measure(@RequestBody MeasureArgs arg) {
        DeviceDevice fms = deviceService.getDeviceBySn(arg.getDiskSn());
        DeviceDevice parent = deviceService.getById(fms.getParentId());
        // 获取最新状态
        DeviceMachineFms fmsData = fmsService.selectLastFmsData(fms.getDeviceSn());
        if (fmsData == null || fmsData.getState().equals("1")) {
            return R.error(-1, "设备不在位或繁忙");
        }
        String ip = fms.isOTDR() ? fms.getIpaddr() : parent.getIpaddr();
        int port = fms.isOTDR() ? fms.getDevicePort() : parent.getDevicePort();
        Integer measureDeviceId = fms.getDeviceId();
        String measureDeviceSn = fms.getDeviceSn();
        Integer endPosition = Double.valueOf(fmsData.getEndPosition()).intValue();
        Integer pulseWidth = Double.valueOf(fmsData.getPulseWidth()).intValue();
        BigDecimal resolution = new BigDecimal(fmsData.getResolution());
        Integer routeId = arg.getRouteId();
        if (StringUtils.isEmpty(arg.getEndPosition()) && StringUtils.isEmpty(arg.getPulseWidth())) {
            final DeviceRouteConfig routeConfig = routeConfigService.getOne(new QueryWrapper<DeviceRouteConfig>()
                    .eq("route_id", arg.getRouteId()).eq("channel", arg.getChannel()));
            if (routeConfig == null) {
                return R.error("该通道高级参数未配置");
            }
            Boolean setResult = fmsDeviceUtil.setFmsConfig(fms.getLayerRow(), ip, port,
                    routeConfig.getEndPosition() + "", routeConfig.getPulseWidth() + "",
                    routeConfig.getResolution() + "", fms.getDeviceType(), fms.getDeviceSn());
            if (!setResult) {
                return R.error("FMS参数设置不成功，请稍后再试");
            }
            endPosition = routeConfig.getEndPosition();
            pulseWidth = routeConfig.getPulseWidth();
            resolution = routeConfig.getResolution();
            final DeviceRoute route = routeService.getById(arg.getRouteId());
            routeId = route.getRouteId();
            if (route.getRouteType().equals("pollingRoute") || route.getRouteType().equals("offlineRoute")) {
                // 需要下发光开关设置
                final DeviceMachineOsw osw = oswService.selectLastOswData(route.getOswSn());
                if (osw == null) {
                    return R.error("OSW设备不存在，请重新绑定");
                }
                measureDeviceId = osw.getDeviceId();
                measureDeviceSn = route.getOswSn();
                final boolean oswSetResult = oswDeviceUtil.setOswConfig(route.getOswSn(), arg.getChannel() + "",
                        parent.getIpaddr(), parent.getDevicePort());
                if (!oswSetResult) {
                    return R.error("OSW参数设置不成功，请稍后再试");
                }
            }
        } else {
            Boolean setResult = fmsDeviceUtil.setFmsConfig(fms.getLayerRow(), ip, port, arg.getEndPosition() + "",
                    arg.getPulseWidth() + "", arg.getResolution() + "", fms.getDeviceType(), fms.getDeviceSn());
            if (!setResult) {
                return R.error("FMS参数设置不成功，请稍后再试");
            }
        }

        String manualKey = Constant.MSP2000MeasureNowMapPrefix + fms.getDeviceSn();
        LocalDateTime now = LocalDateTime.now();
        boolean startResult = fmsDeviceUtil.startMeasure(fms.getLayerRow(), ip, port, fms.getDeviceType());
        if (startResult) {
            DeviceMeasure measure = new DeviceMeasure().setAverageNum(1).setDeviceId(measureDeviceId)
                    .setDeviceSn(measureDeviceSn).setDeviceIp(parent.getIpaddr()).setDeptId(fms.getDeptId())
                    .setAction(3).setEndPosition(endPosition).setPulseWidth(pulseWidth).setMeasureStatus(2)
                    .setStartTime(now).setResolution(resolution).setCreateBy(getUser().getUsername()).setCreateTime(now)
                    .setChannel(arg.getChannel()).setRouteId(routeId);
            measure.setAutoTaskNum(CommonUtil.getOrderIdByUUId());
            measure.insert();
            ConcurrentHashMapCacheUtils.setCache(manualKey, measure);
            return R.ok().putData(measure.getAutoTaskNum());
        }
        return R.error("设备响应不成功，请稍后再试");
    }

    @PostMapping("/measure/clear")
    // "清空指定路由的fms测量数据", notes = "清空指定路由的fms测量数据")
    public R clear(@RequestBody JSONObject jsonObject) {
        String deviceSn = jsonObject.getString("deviceSn");
        Integer routeId = jsonObject.getInteger("routeId");
        boolean clearResult;
        if (StringUtils.isNotEmpty(deviceSn)) {
            clearResult = measureService.remove(new QueryWrapper<DeviceMeasure>().eq("device_sn", deviceSn)
                    .and(i -> i.isNull("standard").or().ne("standard", 1)));
        } else {
            DeviceRoute route = routeService.getById(routeId);
            DeviceMachineFms fmsData = fmsService.selectLastFmsData(route.getFmsSn());
            if (fmsData == null || fmsData.getState().equals("1")) {
                return R.error("设备不在位或正在测试");
            }
            clearResult = measureService.remove(new QueryWrapper<DeviceMeasure>().eq("route_id", routeId)
                    .and(i -> i.isNull("standard").or().ne("standard", 1)));
        }
        return R.trueOrFalse(clearResult);
    }

    @RequestMapping(value = "export")
    public R export(DeviceMeasureParam params) throws IOException {
        List<DeviceMeasure> list = measureService.exportList(params);
        if (list.size() > 50000) {
            return R.error("列表长度超过excel限制(50000)，请分批导出");
        }
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet sheet = workbook.createSheet("光缆列表");
        String dateString = DateUtils.formatLocalDateTime(LocalDateTime.now(), DateUtils.Pay_DATE_TIME_PATTERN);
        String fileName = "设备" + list.get(0).getDeviceName() + "测试历史" + dateString + ".xls";// 设置要导出的文件的名字

        Map<String, CellStyle> styles = ExcelImport.createStyles(workbook);

        // 新增数据行，并且设置单元格数据
        int rowNum = 0;
        String[] headers = { "序号", "设备名称", "设备SN", "设备IP地址", "端口", "对应缆段纤芯", "测试类型", "光缆长度(km)", "衰耗（dB）", "测试时间" };

        rowNum = ExcelImport.initialize(rowNum, "设备" + list.get(0).getDeviceName() + "测试历史", headers, workbook, sheet,
                styles);

        // 在表中存放查询到的数据放入对应的列
        int dataIndex = 1;
        for (DeviceMeasure f : list) {
            HSSFRow row1 = sheet.createRow(rowNum++);
            row1.createCell(0).setCellValue(dataIndex);
            row1.createCell(1).setCellValue(f.getDeviceName());
            row1.createCell(2).setCellValue(f.getDeviceSn());
            row1.createCell(3).setCellValue(ExcelImport.convertNullString(f.getDeviceIp()));
            row1.createCell(4).setCellValue(ExcelImport.convertNullString(f.getChannel()));
            row1.createCell(5).setCellValue(ExcelImport.convertNullString(f.getFibreCoreName()));
            row1.createCell(6).setCellValue(f.getAction() == 1 ? "自动测试" : "专家测试");
            row1.createCell(7).setCellValue(ExcelImport.convertNullString(f.getLength()));
            row1.createCell(8).setCellValue(ExcelImport.convertNullString(f.getPadControl()));
            row1.createCell(9).setCellValue(ExcelImport.convertNullString(f.getEndTime()));
            dataIndex++;
        }
        try {
            File path = new File(Constant.EXPORTPATH);
            if (!path.exists()) {
                path.mkdir();
            }
            File f = new File(path.getAbsolutePath() + "/excel/", fileName);
            if (!f.getParentFile().exists()) {
                f.getParentFile().mkdir();
            }
            FileOutputStream fileOutputStream = new FileOutputStream(f);// 指定路径与名字和格式
            workbook.write(fileOutputStream);// 将数据写出去
            fileOutputStream.close();// 关闭输出流
            return R.ok().putData("/excel/" + fileName);
        } catch (Exception e) {
            e.printStackTrace();
            return R.error(-1, e.getMessage());
        }
    }

    @GetMapping("/standard")
    // "获取指定通道的标准值", notes = "获取指定通道的标准值")
    public R getStandard(String deviceSn, int channel) {
        Assert.isBlank(deviceSn, "deviceSn参数错误");
        Assert.intIsLessEqZero(channel, "channel参数错误");
        DeviceMeasure m = measureService.getOne(new QueryWrapper<DeviceMeasure>().eq("device_sn", deviceSn)
                .eq("standard", true).eq("channel", channel).orderByDesc("measure_id").last("LIMIT 1"));
        if (m == null) {
            return R.error(-1, "该通道未查询到标准值");
        }
        return parseSorAndEvent(m);

    }

    @PostMapping("/standard")
    // "设置标准值", notes = "设置标准值")
    // @RequiresPermissions("bss:device:measure:standard")
    public R standard(@RequestBody DeviceMeasure measure) {
        boolean result = false;
        if (measure.getMeasureId() > 0) {
            DeviceMeasure dbMeasure = measureService.getById(measure.getMeasureId());
            if (dbMeasure != null) {
                result = measureService.setStandardMeasure(dbMeasure);
            }
        }
        return R.trueOrFalse(result);
    }

    /**
     * 获取测量高级配置
     * 
     * @return 高级参数
     */
    @GetMapping("/config")
    public R getConfig(DeviceMachineFms fms) {
        DeviceDevice dd = deviceService.getDeviceBySn(fms.getDiskSn());
        Assert.isNull(dd, "设备不存在，请确认sn是否正确");
        DeviceDevice parent = deviceService.getById(dd.getParentId());
        String ip = dd.isOTDR() ? dd.getIpaddr() : parent.getIpaddr();
        int port = dd.isOTDR() ? dd.getDevicePort() : parent.getDevicePort();
        Map<String, String> map = new HashMap<>();
        String measureTime = fmsDeviceUtil.readFMSMeasureTime(dd.getLayerRow(), ip, port, dd.getOTDRType());
        map.put("measureTime", measureTime);
        final String refIndex = fmsDeviceUtil.readFMSRefIndex(dd.getLayerRow(), ip, port, dd.getOTDRType());
        map.put("refIndex", refIndex);
        final String endOfFiberThreshold = fmsDeviceUtil.readFmsEndOfFiberThreshold(dd.getLayerRow(), ip, port,
                dd.getOTDRType());
        map.put("endOfFiberThreshold", endOfFiberThreshold);
        final String reflectanceThreshold = fmsDeviceUtil.readFmsReflectanceThreshold(dd.getLayerRow(), ip, port,
                dd.getOTDRType());
        map.put("reflectanceThreshold", reflectanceThreshold);
        final String spliceLossThreshold = fmsDeviceUtil.readFmsSpliceLossThreshold(dd.getLayerRow(), ip, port,
                dd.getOTDRType());
        map.put("spliceLossThreshold", spliceLossThreshold);
        return R.ok().putData(map);
    }

    @PostMapping("/config")
    // "设置测量高级参数", notes = "设置测量高级参数")
    public R setConfig(@RequestBody JSONObject json) {
        String sn = json.getString("diskSn");
        JSONArray array = new JSONArray();
        array.add(new JSONObject().fluentPut("configName", "measureTime").fluentPut("configValue",
                json.getString("measureTime")));
        array.add(new JSONObject().fluentPut("configName", "spliceLossThreshold").fluentPut("configValue",
                json.getString("spliceLossThreshold")));
        array.add(new JSONObject().fluentPut("configName", "endOfFiberThreshold").fluentPut("configValue",
                json.getString("endOfFiberThreshold")));
        array.add(new JSONObject().fluentPut("configName", "reflectanceThreshold").fluentPut("configValue",
                json.getString("reflectanceThreshold")));
        array.add(new JSONObject().fluentPut("configName", "refIndex").fluentPut("configValue",
                json.getString("refIndex")));

        DeviceDevice dd = deviceService.getDeviceBySn(sn);
        Assert.isNull(dd, "FMS设备不存在或已移除");
        DeviceDevice parent = deviceService.getById(dd.getParentId());
        String ip = dd.isOTDR() ? dd.getIpaddr() : parent.getIpaddr();
        int port = dd.isOTDR() ? dd.getDevicePort() : parent.getDevicePort();
        int successCount = 0;
        DeviceMachineFms fms = fmsService.selectLastFmsData(sn);
        if (fms == null) {
            fms = new DeviceMachineFms();
            fms.setDeviceId(dd.getDeviceId());
            fms.setDiskSn(dd.getDeviceSn());
        }
        for (Object o : array) {
            JSONObject c = (JSONObject) o;
            String configName = c.getString("configName");
            String configValue = c.getString("configValue");

            switch (configName) {
                case "measureTime":
                    double time = Double.parseDouble(configValue);
                    if (fmsDeviceUtil.setFmsTime(dd.getLayerRow(), ip, port, (int) time, dd.getDeviceType())) {
                        successCount++;
                        fms.setMeasureTime((int) time);
                    }

                    break;
                case "refIndex":
                    if (fmsDeviceUtil.setRefIndex(dd.getLayerRow(), ip, port, configValue, dd.getDeviceType())) {
                        fms.setRefIndex(configValue);
                        successCount++;
                    }

                    break;
                case "endOfFiberThreshold":
                    if (fmsDeviceUtil.setFmsEndOfFiberThreshold(dd.getLayerRow(), ip, port, configValue,
                            dd.getDeviceType())) {
                        // fms.setEndPosition(configValue);
                        successCount++;
                    }

                    break;
                case "reflectanceThreshold":
                    double reflectanceThreshold = Double.parseDouble(configValue);
                    if (fmsDeviceUtil.setFmsReflectanceThreshold(dd.getLayerRow(), ip, port, (int) reflectanceThreshold,
                            dd.getDeviceType())) {
                        successCount++;
                    }

                    break;
                case "spliceLossThreshold":
                    if (fmsDeviceUtil.setFmsSpliceLossThreshold(dd.getLayerRow(), ip, port, configValue,
                            dd.getDeviceType()))
                        successCount++;
                    break;
                default:
                    break;
            }

        }
        fmsService.saveOrUpdate(fms);
        return R.ok().putData(successCount);
    }

    /**
     * 将测试的sor信息解析并组包
     *
     * @param m 测量信息
     * @return R
     */
    private R parseSorAndEvent(DeviceMeasure m) {
        if (m == null)
            return R.error(-1, "未查询到测量信息");
        SorFileParser sor = null;
        try {
            if (org.apache.commons.lang.StringUtils.isEmpty(m.getSorPath())) {
                return R.error(-1, "未查询到测量文件");
            }
            sor = SORFileParserTool.parserSorFile(m.getSorPath());
            List<DeviceMeasureEvent> events = measureEventService
                    .list(new QueryWrapper<DeviceMeasureEvent>().eq("measure_id", m.getMeasureId()));
            if (events != null) {
                events.sort(Comparator.comparing(DeviceMeasureEvent::getEventNumber));
            }
            sor.setMeasureId(m.getMeasureId());
            HashMap<String, Object> map = new HashMap<String, Object>();
            map.put("measure", m);
            map.put("sor", sor);
            map.put("events", events);
            return R.ok().putData(map);
        } catch (FileLengthNotEnoughException e) {
            logger.error(e.getMessage());
            return R.error(-1, "文件解析出错！");
        }
    }

}
